package graph;

import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import org.apache.commons.collections15.Transformer;

/*
 * @author Fabio Leardini
 */
public class GrafosTema1 implements ActionListener {

    static int edgeCount = 0;
    
    Graph<MyNode, MyLink> g;
    
    MyNode rm64407, rm64464, rm63693, rm64065, rm60831, rm61552, rm61582, rm61197, rm61890, rm60373, rm63590, rm63548, rm63602, rm61747, rm62029, rm63832, rm62470, rm62150,
            rm64331, rm62610, rm62889, rm641094, rm63920, rm63940, rm63550, rm63782, rm63624, rm63569, rm63913, rm64031, rm64503, rm63598, rm63579, rm64030, rm63614, rm64219,
            rm63919, rm64014, rm6037, rm64094, rm603544, rm64268, rm63917, rm63921, rm64218, rm64334, rm60354;

    public GrafosTema1() {

        // Grafo<V, E> onde V é o tipo dos vértices e E é o tipo das arestas
        g = new DirectedSparseMultigraph<MyNode, MyLink>();
        
        //<editor-fold defaultstate="" desc="Instanciação dos Vértices">
        rm64407 = new MyNode(64407); rm64464 = new MyNode(64464); rm63693 = new MyNode(63693); rm64065 = new MyNode(64065); rm60831 = new MyNode(60831); rm61552 = new MyNode(61552); 
        rm61582 = new MyNode(61582); rm61197 = new MyNode(61197); rm61890 = new MyNode(61890); rm60373 = new MyNode(60373); rm63590 = new MyNode(63590); rm63548 = new MyNode(63548); 
        rm63602 = new MyNode(63602); rm61747 = new MyNode(61747); rm62029 = new MyNode(62029); rm63832 = new MyNode(63832); rm62470 = new MyNode(62470); rm62150 = new MyNode(62150); 
        rm64331 = new MyNode(64331); rm62610 = new MyNode(62610); rm62889 = new MyNode(62889); rm641094 = new MyNode(641094); rm63920 = new MyNode(63920); rm63940 = new MyNode(63940); 
        rm63550 = new MyNode(63550); rm63782 = new MyNode(63782); rm63624 = new MyNode(63624); rm63569 = new MyNode(63569); rm63913 = new MyNode(63913); rm64031 = new MyNode(64031); 
        rm64503 = new MyNode(64503); rm63598 = new MyNode(63598); rm63579 = new MyNode(63579); rm64030 = new MyNode(64030); rm63614 = new MyNode(63614); rm64219 = new MyNode(64219); 
        rm63919 = new MyNode(63919); rm64014 = new MyNode(64014); rm6037 = new MyNode(6037); rm64094 = new MyNode(64094); rm603544 = new MyNode(603544); rm64268 = new MyNode(64268); 
        rm63917 = new MyNode(63917); rm63921 = new MyNode(63921); rm64218 = new MyNode(64218); rm64334 = new MyNode(64334); rm60354 = new MyNode(60354);
        //</editor-fold>
        
        //<editor-fold defaultstate="" desc="Criação das Arestas">
        g.addEdge(new MyLink(100.0, 48), rm60354, rm64407);
        g.addEdge(new MyLink(100.0, 48), rm60354, rm64464);
        g.addEdge(new MyLink(100.0, 48), rm60354, rm63693);
        g.addEdge(new MyLink(100.0, 48), rm60354, rm64065);
        g.addEdge(new MyLink(100.0, 48), rm60831, rm61552);
        g.addEdge(new MyLink(100.0, 48), rm60831, rm61582);

        g.addEdge(new MyLink(100.0, 48), rm61197, rm61890);
        g.addEdge(new MyLink(100.0, 48), rm61197, rm60373);
        g.addEdge(new MyLink(100.0, 48), rm61197, rm63590);
        g.addEdge(new MyLink(100.0, 48), rm61197, rm63548);
        g.addEdge(new MyLink(100.0, 48), rm61197, rm63602);

        g.addEdge(new MyLink(100.0, 48), rm61552, rm60831);

        g.addEdge(new MyLink(100.0, 48), rm61747, rm61747); //Verificar regra de auto-relação

        g.addEdge(new MyLink(100.0, 48), rm62029, rm63832);
        g.addEdge(new MyLink(100.0, 48), rm62029, rm62470);
        g.addEdge(new MyLink(100.0, 48), rm62029, rm62150);
        g.addEdge(new MyLink(100.0, 48), rm62029, rm64331);

        g.addEdge(new MyLink(100.0, 48), rm62150, rm62610);
        g.addEdge(new MyLink(100.0, 48), rm62150, rm62470);
        g.addEdge(new MyLink(100.0, 48), rm62150, rm62029);
        g.addEdge(new MyLink(100.0, 48), rm62150, rm62889);

        g.addEdge(new MyLink(100.0, 48), rm62470, rm62150);
        g.addEdge(new MyLink(100.0, 48), rm62470, rm62029);
        g.addEdge(new MyLink(100.0, 48), rm62470, rm641094);
        g.addEdge(new MyLink(100.0, 48), rm62470, rm63832);

        g.addEdge(new MyLink(100.0, 48), rm62610, rm62150);
        g.addEdge(new MyLink(100.0, 48), rm62610, rm62889);
        g.addEdge(new MyLink(100.0, 48), rm62610, rm61582);
        g.addEdge(new MyLink(100.0, 48), rm62610, rm62470);

        g.addEdge(new MyLink(100.0, 48), rm62889, rm62150);
        g.addEdge(new MyLink(100.0, 48), rm62889, rm62470);
        g.addEdge(new MyLink(100.0, 48), rm62889, rm62029);
        g.addEdge(new MyLink(100.0, 48), rm62889, rm62610);
        g.addEdge(new MyLink(100.0, 48), rm62889, rm61582);

        g.addEdge(new MyLink(100.0, 48), rm63548, rm63920);
        g.addEdge(new MyLink(100.0, 48), rm63548, rm63602);
        g.addEdge(new MyLink(100.0, 48), rm63548, rm63940);
        g.addEdge(new MyLink(100.0, 48), rm63548, rm63550);

        g.addEdge(new MyLink(100.0, 48), rm63550, rm63590);
        g.addEdge(new MyLink(100.0, 48), rm63550, rm63782);
        g.addEdge(new MyLink(100.0, 48), rm63550, rm64065);
        g.addEdge(new MyLink(100.0, 48), rm63550, rm63624);

        g.addEdge(new MyLink(100.0, 48), rm63569, rm63913);
        g.addEdge(new MyLink(100.0, 48), rm63569, rm64031);
        g.addEdge(new MyLink(100.0, 48), rm63569, rm64503);
        g.addEdge(new MyLink(100.0, 48), rm63569, rm63782);
        g.addEdge(new MyLink(100.0, 48), rm63569, rm63598);

        g.addEdge(new MyLink(100.0, 48), rm63579, rm64030);
        g.addEdge(new MyLink(100.0, 48), rm63569, rm63614);
        g.addEdge(new MyLink(100.0, 48), rm63569, rm64219);

        g.addEdge(new MyLink(100.0, 48), rm63590, rm63782);
        g.addEdge(new MyLink(100.0, 48), rm63590, rm63550);
        g.addEdge(new MyLink(100.0, 48), rm63590, rm63919);
        g.addEdge(new MyLink(100.0, 48), rm63590, rm64014);

        g.addEdge(new MyLink(100.0, 48), rm63598, rm63913);
        g.addEdge(new MyLink(100.0, 48), rm63598, rm63782);
        g.addEdge(new MyLink(100.0, 48), rm63598, rm64503);
        g.addEdge(new MyLink(100.0, 48), rm63598, rm63550);

        g.addEdge(new MyLink(100.0, 48), rm63602, rm63548);
        g.addEdge(new MyLink(100.0, 48), rm63602, rm63920);
        g.addEdge(new MyLink(100.0, 48), rm63602, rm63940);
        g.addEdge(new MyLink(100.0, 48), rm63602, rm6037);
        g.addEdge(new MyLink(100.0, 48), rm63602, rm61197);

        g.addEdge(new MyLink(100.0, 48), rm63614, rm64219);
        g.addEdge(new MyLink(100.0, 48), rm63614, rm63579);
        g.addEdge(new MyLink(100.0, 48), rm63614, rm64030);

        g.addEdge(new MyLink(100.0, 48), rm63624, rm64094);
        g.addEdge(new MyLink(100.0, 48), rm63624, rm64407);
        g.addEdge(new MyLink(100.0, 48), rm63624, rm64014);
        g.addEdge(new MyLink(100.0, 48), rm63624, rm63624);
        g.addEdge(new MyLink(100.0, 48), rm63624, rm63550);

        g.addEdge(new MyLink(100.0, 48), rm63693, rm64464);
        g.addEdge(new MyLink(100.0, 48), rm63693, rm603544);
        g.addEdge(new MyLink(100.0, 48), rm63693, rm64407);
        g.addEdge(new MyLink(100.0, 48), rm63693, rm64094);
        g.addEdge(new MyLink(100.0, 48), rm63693, rm64065);

        g.addEdge(new MyLink(100.0, 48), rm63782, rm63913);
        g.addEdge(new MyLink(100.0, 48), rm63782, rm63550);
        g.addEdge(new MyLink(100.0, 48), rm63782, rm63590);
        g.addEdge(new MyLink(100.0, 48), rm63782, rm63598);

        g.addEdge(new MyLink(100.0, 48), rm63832, rm64094);
        g.addEdge(new MyLink(100.0, 48), rm63832, rm62029);
        g.addEdge(new MyLink(100.0, 48), rm63832, rm64331);
        g.addEdge(new MyLink(100.0, 48), rm63832, rm64065);

        g.addEdge(new MyLink(100.0, 48), rm63913, rm63598);
        g.addEdge(new MyLink(100.0, 48), rm63913, rm63782);
        g.addEdge(new MyLink(100.0, 48), rm63913, rm63569);
        g.addEdge(new MyLink(100.0, 48), rm63913, rm63550);
        g.addEdge(new MyLink(100.0, 48), rm63913, rm64268);

        g.addEdge(new MyLink(100.0, 48), rm63917, rm64031);
        g.addEdge(new MyLink(100.0, 48), rm63917, rm63921);
        g.addEdge(new MyLink(100.0, 48), rm63917, rm64218);
        g.addEdge(new MyLink(100.0, 48), rm63917, rm63569);
        g.addEdge(new MyLink(100.0, 48), rm63917, rm63913);

        g.addEdge(new MyLink(100.0, 48), rm63919, rm64014);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm60373);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm63550);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm63624);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm63590);

        g.addEdge(new MyLink(100.0, 48), rm63921, rm63917);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm64218);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm64031);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm63569);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm63913);

        g.addEdge(new MyLink(100.0, 48), rm64014, rm63919);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm64331);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm64094);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm63624);
        g.addEdge(new MyLink(100.0, 48), rm63919, rm64334);

        g.addEdge(new MyLink(100.0, 48), rm64031, rm63921);
        g.addEdge(new MyLink(100.0, 48), rm64031, rm64218);
        g.addEdge(new MyLink(100.0, 48), rm64031, rm63917);
        g.addEdge(new MyLink(100.0, 48), rm64031, rm64268);
        g.addEdge(new MyLink(100.0, 48), rm64031, rm63569);

        g.addEdge(new MyLink(100.0, 48), rm64065, rm63832);
        g.addEdge(new MyLink(100.0, 48), rm64065, rm64331);
        g.addEdge(new MyLink(100.0, 48), rm64065, rm64503);
        g.addEdge(new MyLink(100.0, 48), rm64065, rm63550);
        g.addEdge(new MyLink(100.0, 48), rm64065, rm64031);

        g.addEdge(new MyLink(100.0, 48), rm64094, rm64334);
        g.addEdge(new MyLink(100.0, 48), rm64094, rm63832);
        g.addEdge(new MyLink(100.0, 48), rm64094, rm63624);
        g.addEdge(new MyLink(100.0, 48), rm64094, rm64014);

        g.addEdge(new MyLink(100.0, 48), rm64218, rm63921);
        g.addEdge(new MyLink(100.0, 48), rm64218, rm63917);
        g.addEdge(new MyLink(100.0, 48), rm64218, rm64031);
        g.addEdge(new MyLink(100.0, 48), rm64218, rm63913);

        g.addEdge(new MyLink(100.0, 48), rm64219, rm63579);
        g.addEdge(new MyLink(100.0, 48), rm64218, rm63614);
        g.addEdge(new MyLink(100.0, 48), rm64218, rm64030);

        g.addEdge(new MyLink(100.0, 48), rm64331, rm64065);
        g.addEdge(new MyLink(100.0, 48), rm64331, rm64503);
        g.addEdge(new MyLink(100.0, 48), rm64331, rm63832);
        g.addEdge(new MyLink(100.0, 48), rm64331, rm63550);
        g.addEdge(new MyLink(100.0, 48), rm64331, rm62029);

        g.addEdge(new MyLink(100.0, 48), rm64407, rm60354);
        g.addEdge(new MyLink(100.0, 48), rm64407, rm64464);
        g.addEdge(new MyLink(100.0, 48), rm64407, rm63624);
        g.addEdge(new MyLink(100.0, 48), rm64407, rm63550);

        g.addEdge(new MyLink(100.0, 48), rm64464, rm60354);
        g.addEdge(new MyLink(100.0, 48), rm64464, rm63693);
        g.addEdge(new MyLink(100.0, 48), rm64464, rm64407);
        g.addEdge(new MyLink(100.0, 48), rm64464, rm64065);

        g.addEdge(new MyLink(100.0, 48), rm64503, rm63569);
        g.addEdge(new MyLink(100.0, 48), rm64503, rm63598);
        g.addEdge(new MyLink(100.0, 48), rm64503, rm63782);
        g.addEdge(new MyLink(100.0, 48), rm64503, rm63913);
        g.addEdge(new MyLink(100.0, 48), rm64503, rm64065);
        //</editor-fold>        
    }

    public void calcUnweightedShortestPath() {

        try {
            DijkstraShortestPath<MyNode, MyLink> alg = new DijkstraShortestPath(g);

            List<MyLink> l = alg.getPath(rm61197, rm63602);

            JOptionPane.showMessageDialog(null, "O menor caminho de " + rm61197 + " para " + rm63602 + " é: " + l.toString(), "Resultado", JOptionPane.INFORMATION_MESSAGE);
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "RM informado incorretamente ou não existente!", "Erro", JOptionPane.ERROR_MESSAGE);
            System.out.println(ex);
        }
    }

    public void calcWeightedShortestPath() {

        try {
            Transformer<MyLink, Double> wtTransformer = new Transformer<MyLink, Double>() {

                public Double transform(MyLink link) {
                    return link.weight;
                }
            };

            DijkstraShortestPath<MyNode, MyLink> alg = new DijkstraShortestPath(g, wtTransformer);

            List<MyLink> l = alg.getPath(rm64503, rm63569);

            Number dist = alg.getDistance(rm64503, rm63569);

            JOptionPane.showMessageDialog(null, "O maior caminho de " + rm64503 + "para" + rm63569 + " é "
                    + l.toString() + " e o comprimento do caminho é: " + dist, "Resultado", JOptionPane.INFORMATION_MESSAGE);
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "RM informado incorretamente ou não existente!", "Erro", JOptionPane.ERROR_MESSAGE);
            System.out.println(ex);
        }
    }

    @SuppressWarnings("empty-statement")
    public void popUp(String acao) {

            GrafosTema1 grafos = new GrafosTema1();

            if (acao.equals("menor")) {
                grafos.calcUnweightedShortestPath();
            } else if (acao.equals("maior")) {
                grafos.calcWeightedShortestPath();
            }
    }

    public static void main(String[] args) {

        GrafosTema1 sgv = new GrafosTema1(); // Cria o grafo

        //Cria layout do grafo
        Layout<MyNode, MyLink> layout = new CircleLayout(sgv.g);
        layout.setSize(new Dimension(1000, 1000));

        VisualizationViewer<MyNode, MyLink> vv = new VisualizationViewer<MyNode, MyLink>(layout);
        vv.setPreferredSize(new Dimension(1000, 1000));
        vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
        vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller());

        // Possibilidade de interação com mouse
        DefaultModalGraphMouse gm = new DefaultModalGraphMouse();
        gm.setMode(ModalGraphMouse.Mode.TRANSFORMING);
        vv.setGraphMouse(gm);

        JFrame frame = new JFrame("Grafo Interativo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(vv);
        frame.pack();
        frame.setVisible(true);

        //<editor-fold defaultstate="" desc="Criação do Menu">
        JMenuBar menuBar = new JMenuBar();

        JMenu opcoes = new JMenu("Opções");
        opcoes.setPreferredSize(new Dimension(80, 20));

        JMenuItem menor = new JMenuItem("Menor Caminho");
        menor.setMnemonic('e');
        ActionListener lst = new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                GrafosTema1 g = new GrafosTema1();
                g.popUp("menor");
            }
        };
        menor.addActionListener(lst);
        opcoes.add(menor);

        JMenuItem maior = new JMenuItem("Maior Caminho");
        maior.setMnemonic('a');
        lst = new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                GrafosTema1 g = new GrafosTema1();
                g.popUp("maior");
            }
        };
        maior.addActionListener(lst);
        opcoes.add(maior);
        
        opcoes.addSeparator();

        JMenuItem sair = new JMenuItem("Sair");
        sair.setMnemonic('s');
        lst = new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        };
        sair.addActionListener(lst);
        opcoes.add(sair);

        menuBar.add(opcoes);
        frame.setJMenuBar(menuBar);
        frame.pack();
        frame.setVisible(true);
        //</editor-fold>
        
        JOptionPane.showMessageDialog(null, "Este grafo é interativo. Utilize o scroll do mouse para zoom e clique e arraste para move-lo.", "Grafo Interativo", JOptionPane.PLAIN_MESSAGE);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}